package com.smfx.yxt.excel.tags;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.util.CellRangeAddress;

import com.smfx.yxt.excel.ExcelParser;
import com.smfx.yxt.excel.ExcelUtils;
import com.smfx.yxt.excel.WorkbookUtils;

/**
 * <p>
 * <b>EachTag </b> is a class which parse the #each tag
 * </p>
 * <p>
 * #each .. ... on ..
 * </p>
 */
public class EachTag implements ITag {

    public static final String KEY_EACH = "#each";

    public int[] parseTag(HSSFSheet sheet, HSSFRow curRow, HSSFCell curCell) {
        String expr = "";
        String each = curCell.getRichStringCellValue().getString();
        StringTokenizer st = new StringTokenizer(each, " ");
        String widthstr = "";
        String onstr = "";
        int pos = 0;
        while (st.hasMoreTokens()) {
            String str = st.nextToken();
            if (pos == 1) {
                expr = str;
            }
            if (pos == 2 && !"on".equals(str)) {
                widthstr = str;
            }
            if (pos == 3 && !"on".equals(str)) {
                onstr = str;
            }
            if (pos == 4) {
                onstr = str;
            }
            pos++;
        }

        int[] widths = new int[0];
        if (null != widthstr && !"".equals(widthstr)) {
            Object o = ExcelParser.parseExpr(widthstr);
            if (null != o) {
                if (o.getClass().isArray()) {
                    widths = new int[Array.getLength(o)];
                    for (int i = 0; i < widths.length; i++) {
                        widths[i] = Integer.parseInt(Array.get(o, i).toString());
                    }
                }
                else if (o instanceof Collection) {
                    Collection list = (Collection)o;
                    widths = new int[list.size()];
                    int i = 0;
                    for (Object object : list) {
                        widths[i] = Integer.parseInt(object.toString());
                        i++;
                    }
                }
                else {
                    String[] s = o.toString().split(",");
                    widths = new int[s.length];
                    for (int i = 0; i < widths.length; i++) {
                        widths[i] = Integer.parseInt(s[i]);
                    }
                }
            }
        }

        Object obj = ExcelParser.parseExpr(expr);
        if (null == obj)
            return new int[] { 0, 0, 0 };

        // by onstr get the property
        if (!"".equals(onstr)) {
            obj = ExcelParser.parseExpr(onstr);
            if (null == obj)
                return new int[] { 0, 0, 0 };
        }

        // iterator properties
        Iterator it = ExcelParser.getIterator(obj);
        if (null == it) {
            if (obj instanceof DynaBean) {
                it = ExcelParser.getIterator(ExcelParser.getBeanProperties(((DynaBean)obj).getDynaClass()));
            }
            else {
                it = ExcelParser.getIterator(ExcelParser.getBeanProperties(obj.getClass()));
            }
        }
        if (null == it) {
            return new int[] { 0, 0, 0 };
        }

        int index = 0;
        int arrayIndex = 0;
        int eachPos = curCell.getColumnIndex();
        String modelName = expr.substring(ExcelParser.EXPR_OPEN.length(),
                expr.length() - ExcelParser.EXPR_CLOSE.length());

        // restore the obj
        obj = ExcelParser.parseExpr(expr);
        while (it.hasNext()) {
            Object o = it.next();
            String property = "";
            Object value = null;
            if (o instanceof Field) {
                property = ((Field)o).getName();
            }
            else if (o instanceof Map.Entry) {
                property = ((Map.Entry)o).getKey().toString();
            }
            else if (o instanceof DynaProperty) {
                property = ((DynaProperty)o).getName();
            }
            else {
                property = o != null ? o.toString() : null;
            }

            // test the object is array/list or other
            if (obj.getClass().isArray() || obj instanceof Collection) {
                property = modelName + "[" + arrayIndex++ + "]";
            }
            else if (property != null) {
                property = modelName + "." + property;
            }
            if (property != null) {
                value = ExcelParser.getValue(property);
            }
            if (null == value)
                value = "";

            if (ExcelUtils.isCanShowType(value)) {

                // get cell merge count
                int width = 1;
                if (index < widths.length) {
                    width = widths[index];
                }
                else if (1 == widths.length) {
                    width = widths[0];
                }

                // get row merged of the curCell
                int rowMerged = 1;
                for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
                    CellRangeAddress r = sheet.getMergedRegion(i);
                    if (r.getFirstRow() == curRow.getRowNum() && r.getFirstColumn() == curCell.getColumnIndex()
                            && r.getLastColumn() == curCell.getColumnIndex()) {
                        rowMerged = r.getLastRow() - r.getFirstRow() + 1;
                        break;
                    }
                }

                HSSFCell cell = WorkbookUtils.getCell(curRow, eachPos);

                // shift the after cell
                if (index > 0) {
                    WorkbookUtils.shiftCell(sheet, curRow, cell, 1, rowMerged);
                }
                if (width > 1) {
                    HSSFCell nextCell = WorkbookUtils.getCell(curRow, eachPos + 1);
                    WorkbookUtils.shiftCell(sheet, curRow, nextCell, width - 1, rowMerged);
                }

                // copy the style of curCell
                for (int rownum = curRow.getRowNum(); rownum < curRow.getRowNum() + rowMerged; rownum++) {
                    for (int i = 0; i < width; i++) {
                        HSSFRow r = WorkbookUtils.getRow(rownum, sheet);
                        HSSFCell c = WorkbookUtils.getCell(r, eachPos + i);
                        HSSFCell cc = WorkbookUtils.getCell(r, curCell.getColumnIndex());
                        c.setCellStyle(cc.getCellStyle());
                    }
                }

                // merge cells
                if (width > 1 || rowMerged > 1) {
                    sheet.addMergedRegion(new CellRangeAddress(curRow.getRowNum(), curRow.getRowNum() + rowMerged - 1,
                            cell.getColumnIndex(), cell.getColumnIndex() + width - 1));
                }

                cell.setCellValue(new HSSFRichTextString("${" + property + "}"));
                ExcelParser.parseCell(sheet, curRow, cell);

                eachPos += width;
                index++;
            }
        }

        return new int[] { 0, 0, 0 };
    }

    public String getTagName() {
        return KEY_EACH;
    }

    public boolean hasEndTag() {
        return false;
    }
}
